﻿using CatUtils.Utils.IoUtils;
using HostsTool.Currency;
using HostsTool.Currency.IoUtils;
using HostsTool.Currency.View;
using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Text;

namespace HostsTool.Utils
{
    internal class HostEdit
    {
        private string SystemNotePad = new FloderNameHelper().GetFloderPath(Environment.GetFolderPath(Environment.SpecialFolder.System)) + "system32\\notepad.exe";
        private string SystemHost = new FloderNameHelper().GetFloderPath(Environment.GetFolderPath(Environment.SpecialFolder.System)) + "system32\\drivers\\etc\\hosts";

        /// <summary>
        /// 系统文本编辑器
        /// </summary>
        public string SystemNotePad1 { get => SystemNotePad; set => SystemNotePad = value; }

        /// <summary>
        /// 系统Host文件路径
        /// </summary>
        public string SystemHost1 { get => SystemHost; set => SystemHost = value; }

        /// <summary>
        /// 打开文本编辑器帮助
        /// </summary>
        public void OpenNotepadAlert()
        {
            if (MessageHelper.DialogResultAlert("您即将编辑hosts文件，请修改完毕后保存。"))
            {
                OpenNotPad();
            }
            else
                return;
        }

        /// <summary>
        /// 管理员权限打开文本编辑器
        /// </summary>
        public void OpenNotPad()
        {
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.UseShellExecute = true;
            startInfo.FileName = SystemNotePad;
            startInfo.Arguments = SystemHost;
            //设置启动动作,确保以管理员身份运行
            startInfo.Verb = "runas";
            System.Diagnostics.Process.Start(startInfo);
        }

        /// <summary>
        /// 保存Hosts
        /// </summary>
        public void SaveHostsAlert(string DnsIP, string HostUrl)
        {
            if (MessageHelper.DialogResultAlert("杀软提示修改hosts文件请允许，本软件不对第三方DNS返回结果负责，请勿修改支付类网站hosts！"))
            {
                string AlertContent = SaveHosts(DnsIP, HostUrl);
                AlertModfly(HostUrl, AlertContent);
            }
            else
                return;
        }

        /// <summary>
        /// 保存Hosts
        /// </summary>
        /// <param name="DnsIP"></param>
        /// <param name="HostUrl"></param>
        public string SaveHosts(string DnsIP, string HostUrl)
        {
            if (!PingHost(DnsIP))
            {
                MessageHelper.Alert(string.Format("DNS{0}连接失败，请重新选择一个DNS", HostUrl));
                return "";
            }
            List<string> HostIPList = new DnsHelper().GetHostIp(DnsIP, HostUrl);
            if (HostIPList.Count == 0) {
                MessageHelper.Alert(string.Format("域名{0}解析不到结果，请检查域名或换个DNS重试。",HostUrl));
                return null;
            }
            string InvalidIP = "";
            try
            {
                foreach (var item in HostIPList)
                {
                    if (HostUrl.IndexOf("http") >= 0)
                    {
                        HostUrl = new Uri(HostUrl).Host;
                    }
                    string SaveInfo = string.Format("\r\n{0}  {1}  #hosttool {2}", item, HostUrl, DnsIP);
                    if (new HostEdit().PingHost(item))
                    {
                        DeleteOldHost(HostUrl);
                        FileHelper.AppendUTF8Text(SystemHost1, SaveInfo);
                    }
                    else
                        InvalidIP += SaveInfo;
                }
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
            if (InvalidIP != "")
                return "\r\n以下域名修改hosts后依然无法连接，若未能解决您的问题，请点击还原修改。" + InvalidIP;

            return InvalidIP;
        }

        /// <summary>
        /// 删除旧的配置
        /// </summary>
        /// <param name="HostUrl"></param>
        public void DeleteOldHost(string HostUrl)
        {
            List<string> TempList = new List<string>();
            foreach (var item in FileHelper.ReadAllLine(SystemHost1))
            {
                string Url = TextHelper.ReplaceText(item, "(#hosttool.*?|[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})", "").Trim();
                if (Url == "")
                    continue;

                if (Url == HostUrl)
                {
                    continue;
                }
                TempList.Add(item);
            }
            FileHelper.WriteUTF8List(SystemHost1, TempList);
        }

        /// <summary>
        /// 自动分析处理 异步委托
        /// </summary>
        /// <param name="DnsIP"></param>
        /// <param name="HostUrl"></param>
        /// <param name="IgnoreOtherHost"></param>
        public delegate void AutoAnalysisDelegate(string DnsIP, string HostUrl, bool IgnoreOtherHost = true);

        /// <summary>
        /// 自动分析处理
        /// </summary>
        /// <param name="DnsIP"></param>
        /// <param name="HostUrl"></param>
        /// <param name="IgnoreOtherHost">是否忽略不包含主域名的链接</param>
        public void AutoAnalysis(string DnsIP, string HostUrl, bool IgnoreOtherHost = true)
        {
            if (!MessageHelper.DialogResultAlert("杀软提示修改hosts文件请允许，本软件不对第三方DNS返回结果负责，请勿修改支付类网站hosts！"))
                return;
            String AlertContent = SaveHosts(DnsIP, HostUrl);

            string RequestUrl = HostUrl;
            if (RequestUrl.IndexOf("http") != 0 && RequestUrl.IndexOf("https") != 0)
                RequestUrl = "http://" + RequestUrl;
            string Shtml = WebHelper.HttpPcGet(RequestUrl);
            if (Shtml == "")
            {
                MessageHelper.Alert("解析更多信息失败，依然无法打开网站，请还原修改。");
                return;
            }

            List<string> LinkList = new List<string>(); ;

            foreach (var item in TextHelper.RegexTextList(Shtml, "[a-zA-z]+://[^\\s]*"))
            {
                try
                {
                    string UrlHost = item;
                    if (UrlHost.IndexOf("http") >= 0)
                    {
                        UrlHost = new Uri(UrlHost).Host;
                    }
                    if (!LinkList.Contains(UrlHost) && IgnoreOtherHost)
                    {
                        LinkList.Add(UrlHost);
                        Console.WriteLine(UrlHost);
                        AlertContent += SaveHosts(DnsIP, UrlHost);
                    }
                }
                catch (Exception ex)
                {
                    PrintLog.Log(ex);
                }
            }
            AlertModfly(HostUrl, AlertContent);
        }
        /// <summary>
        /// 提示修改
        /// </summary>
        /// <param name="HostUrl"></param>
        /// <param name="AlertContent"></param>
        private static void AlertModfly(string HostUrl, string AlertContent)
        {
            if (AlertContent != "" && AlertContent != null)
                MessageHelper.Alert(AlertContent);

            if (AlertContent != null && MessageHelper.DialogResultAlert("修改完毕，是否立即查看？"))
            {
                if (HostUrl.IndexOf("http") != 0 && HostUrl.IndexOf("https") != 0)
                    HostUrl = "http://" + HostUrl;

                new FloderHelper().OpenFloder(HostUrl);
            }
        }

        /// <summary>
        /// 删除已修改内容
        /// </summary>
        public void DeleteModification()
        {
            List<string> TempList = new List<string>();
            foreach (var item in FileHelper.ReadAllLine(SystemHost1))
            {
                if (item != "" && item.IndexOf("hosttool") < 0)
                {
                    TempList.Add(item);
                }
            }
            FileHelper.WriteUTF8List(SystemHost1, TempList);
            MessageHelper.Alert("还原完毕！");
        }

        /// <summary>
        /// Ping指定的主机，看能否ping通
        /// </summary>
        /// <param name="Address">(主机地址)</param>
        /// <param name="TimeOut">(超时时间,默认:1s)</param>
        /// <returns>True if a response is received, false otherwise</returns>
        public bool PingHost(string Address, int TimeOut = 1000)
        {
            using (System.Net.NetworkInformation.Ping PingSender = new System.Net.NetworkInformation.Ping())
            {
                PingOptions Options = new PingOptions();
                Options.DontFragment = true;
                string Data = "test";
                byte[] DataBuffer = Encoding.ASCII.GetBytes(Data);
                PingReply Reply = PingSender.Send(Address, TimeOut, DataBuffer, Options);
                if (Reply.Status == IPStatus.Success)
                    return true;
                return false;
            }
        }
    }
}